// Copyright (c) 2009, Michael Patraw
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//     * The name of Michael Patraw may not be used to endorse or promote 
//       products derived from this software without specific prior written
//       permission.
//
// THIS SOFTWARE IS PROVIDED BY Michael Patraw ''AS IS'' AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL Michael Patraw BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef ANIMALS_H
#define ANIMALS_H

#include "glyph.h"
#include "items.h"
#include "util.h"

// Conditions.
#define COND_DEAD        (1 << 0)
#define COND_DYING       (1 << 1)
#define COND_TIRED       (1 << 2)
#define COND_HUNGRY      (1 << 3)
#define COND_STARVING    (1 << 4)
#define COND_THIRSTY     (1 << 5)
#define COND_DEHYDRATED  (1 << 6)
#define COND_WATERPOISON (1 << 7)

#define COND_COLD        (1 << 8)
#define COND_HYPOTHERMIA (1 << 9)
#define COND_HOT         (1 << 10)
#define COND_HEATSTROKE  (1 << 11)

const unsigned int INVENTORY_SIZE = 10;

// TODO: needs work.
class Stat
{
public:
    Stat(int max=1) :
    cur_(max), max_(max)
    {
    }
    
    bool isZero() const { return cur_ <= 0; }
    bool isMax() const { return cur_ == max_; }
    
    void setCurrent(int cur) { cur_ = cur; }
    void setMax(int max) { max_ = max; }
    
    void zeroOut() { cur_ = 0; }
    void maxOut() { cur_ = max_; }
    
    int & current() { return cur_; }
    int & max() { return max_; }
protected:
    int cur_, max_;
};

// TODO: needs work.
class Animal
{
public:
    Animal() :
    glyph_(Glyph('?', White)), coord_(0, 0)
    {
    }
    Animal(const Glyph & g, const Coord & c) :
    glyph_(g), coord_(c)
    {
    }
    virtual ~Animal()
    {
    }

    virtual Glyph getGlyph() const { return glyph_; }
    virtual Coord getCoord() const { return coord_; }
    
    virtual Coord & coord() { return coord_; }
    
    virtual void setGlyph(const Glyph & g) { glyph_ = g; }
    virtual void setCoord(const Coord & c) { coord_ = c; }
    
    virtual Stat * health() { return &health_; }
    virtual Stat * attack() { return &attack_; }
    virtual Stat * defense() { return &defense_; }
    
    virtual bool isDead() const { return health_.isZero(); }
    
    virtual void move(int dx, int dy);
protected:
    Glyph glyph_;
    Coord coord_;
    
    Stat health_, attack_, defense_;
};

// TODO: needs work.
class Human : public Animal
{
public:
    Human(const char * name);
    virtual ~Human();
    
    virtual void kill(const char * reason);
    
    virtual const char * getName() const;
    virtual const char * getDeathReason() const;
    
    virtual unsigned int getCondition();
    virtual const char * getConditionNames() const;
    
    virtual bool hasCondition(unsigned int cond);
    virtual void addCondition(unsigned int cond);
    virtual void remCondition(unsigned int cond);
    
    virtual int getWarmth() const;
    virtual int getEnergy() const;
    virtual int getSatiation();
    virtual int getHydration();
    
    virtual void setWarmth(int w);
    virtual void setEnergy(int e);
    virtual void setSatiation(int s);
    virtual void setHydration(int h);
    
    virtual void modWarmth(int dw);
    virtual void modEnergy(int de);
    virtual void modSatiation(int ds);
    virtual void modHydration(int dh);
    
    virtual void update(); // Time has elapsed.
    
    // Item based.
    virtual Item * equip(Item * item);
    
    virtual ItemList * getInv();
    
    virtual Item * getHand();
    virtual Item * getHead();
    virtual Item * getBody();
    virtual Item * getLegs();
    virtual Item * getFeet();
    
    virtual Item * remHand(); // Must be deallocated.
    virtual Item * remHead(); // Must be deallocated.
    virtual Item * remBody(); // Must be deallocated.
    virtual Item * remLegs(); // Must be deallocated.
    virtual Item * remFeet(); // Must be deallocated.
    
    // NOTE: returns false if an item is already set.
    virtual bool setHand(Item * item);
    virtual bool setHead(Item * item);
    virtual bool setBody(Item * item);
    virtual bool setLegs(Item * item);
    virtual bool setFeet(Item * item);
    
    virtual int getTotalItemHealth() const;
    virtual int getTotalItemAttack() const;
    virtual int getTotalItemDefense() const;
    virtual int getTotalItemWarmth() const;
protected:
    const char * name_;
    int warmth_; // -3 to 3 is comfortable.
    int temptimer_;
    int energy_; // Tired level.
    Stat satiation_; // 200 max
    Stat hydration_; // 100 max
    unsigned int condition_;
    ItemList inv_;
    Item * hand_;
    Item * head_;
    Item * body_;
    Item * legs_;
    Item * feet_;
    const char * deathreason_;
private:
    void _updateStats();
    void _updateConditions();
};

// TODO: needs work.
void Attack(Animal & attacker, Animal & defender);

#endif // ANIMALS_H
